/**
 * QUANSHI.com Inc.
 * Copyright (c) 2016-2017 All Rights Reserved.
 */
package com.quanshi.scheduler.core.handler;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.annotation.AnnotationUtils;

import com.quanshi.scheduler.core.executor.IJobExecutor;

import groovy.lang.GroovyClassLoader;

/**
 * groovy工厂
 * 
 * @author chinaxiang
 * @version 2017年7月7日 下午11:40:49
 */
public class GlueFactory {

    @SuppressWarnings("unused")
    private static Logger      logger            = LoggerFactory.getLogger(GlueFactory.class);

    /**
     * groovy class loader
     */
    private GroovyClassLoader  groovyClassLoader = new GroovyClassLoader();

    // ----------------------------- spring support -----------------------------
    private static GlueFactory glueFactory       = new GlueFactory();

    public static GlueFactory getInstance() {
        return glueFactory;
    }

    /**
     * inject action of spring
     * @param instance
     */
    private void injectService(Object instance) {
        if (instance == null) {
            return;
        }

        Field[] fields = instance.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }

            Object fieldBean = null;
            // with bean-id, bean could be found by both @Resource and @Autowired, or bean could only be found by @Autowired
            if (AnnotationUtils.getAnnotation(field, Resource.class) != null) {
                try {
                    Resource resource = AnnotationUtils.getAnnotation(field, Resource.class);
                    if (resource.name() != null && resource.name().length() > 0) {
                        fieldBean = IJobExecutor.applicationContext.getBean(resource.name());
                    } else {
                        fieldBean = IJobExecutor.applicationContext.getBean(field.getName());
                    }
                } catch (Exception e) {
                }
                if (fieldBean == null) {
                    fieldBean = IJobExecutor.applicationContext.getBean(field.getType());
                }
            } else if (AnnotationUtils.getAnnotation(field, Autowired.class) != null) {
                Qualifier qualifier = AnnotationUtils.getAnnotation(field, Qualifier.class);
                if (qualifier != null && qualifier.value() != null && qualifier.value().length() > 0) {
                    fieldBean = IJobExecutor.applicationContext.getBean(qualifier.value());
                } else {
                    fieldBean = IJobExecutor.applicationContext.getBean(field.getType());
                }
            }

            if (fieldBean != null) {
                field.setAccessible(true);
                try {
                    field.set(instance, fieldBean);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // ----------------------------- load instance -----------------------------
    // load new instance, prototype
    public IJobHandler loadNewInstance(String codeSource) throws Exception {
        if (codeSource != null && codeSource.trim().length() > 0) {
            Class<?> clazz = groovyClassLoader.parseClass(codeSource);
            if (clazz != null) {
                Object instance = clazz.newInstance();
                if (instance != null) {
                    if (instance instanceof IJobHandler) {
                        this.injectService(instance);
                        return (IJobHandler) instance;
                    } else {
                        throw new IllegalArgumentException(
                            ">>>>>>>>>>> glue, loadNewInstance error, " + "cannot convert from instance[" + instance.getClass() + "] to IJobHandler");
                    }
                }
            }
        }
        throw new IllegalArgumentException(">>>>>>>>>>> glue, loadNewInstance error, instance is null");
    }
}
